package com.blogs.web.controller;

import com.blogs.common.random.RandomGiftUtils;
import com.blogs.common.response.RetResponse;
import com.blogs.common.response.RetResult;
import com.blogs.model.user.entity.user.UserEntity;
import com.blogs.service.web.WebService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Author: xiaokai
 * @Description:
 * @Date: 2019/6/13
 * @Version: 1.0
 */
@Slf4j
@RequestMapping("/")
@RestController
@Api("PC登录")
public class WebLoginController {

    @Autowired
    private WebService webService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private Redisson redisson;

    @ApiOperation(value = "登录接口", notes = "登录接口")
    @GetMapping(value = "/login")
    public RetResult<UserEntity> login() {
        return RetResponse.makeOKRsp(webService.seleLogin());
    }

    @ApiOperation(value = "注册接口")
    @PostMapping(value = "/registered")
    public RetResult<UserEntity> registered() {
        return RetResponse.makeOKRsp();
    }


    /**
     * 测试处理redis高并发缓存穿透
     *
     * @return
     */
    @GetMapping(value = "/getUserMessage")
    public Object getUserMessage() {
        //线程调用查询用户信息
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                webService.getAllUserMessage();
            }
        };
        //多线程测试一下缓存穿透问题
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 10000; i++) {
            executorService.submit(runnable);
        }
        return webService.getAllUserMessage();
    }

    /**
     * 整合分布式锁处理红包秒杀机制
     * (第一种结合分布式锁处理)
     *
     * @return
     */
    public String redEnvelope1() {
        String lockKey = "hongb";
        String clientId = UUID.randomUUID().toString();
        int bao = 3;//红包个数
        try {
            //处理高并发场景下多个线程访问导致分布式锁的卡死
            Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);//setnx分布式锁
            if (!result) {
                return "error";
            }
            int bigBao = Integer.parseInt(stringRedisTemplate.opsForValue().get("hongbao"));//jedis.get(key)
            if (bigBao > 0) {
                List<Integer> gifts = RandomGiftUtils.randomGifts(bigBao, bao);
                int realBigBao = bigBao - 1;
                stringRedisTemplate.opsForValue().set("hongbao", realBigBao + "");
                System.out.println("当前时间：" + System.currentTimeMillis() + ">>>>>>>>>" + "抢包成功，扣减红包金额:" + realBigBao + "");
            } else {
                System.out.println("抢包失败，扣减红包金额不足>>>>>>>>>" + System.currentTimeMillis());
            }
        } finally {
            if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey)))
                stringRedisTemplate.delete(lockKey);
        }
        return "end";
    }


    /**
     * 测试redis红包并发机制处理（分布式下）
     * (第二种结合redisson处理)
     *
     * @return
     * @throws InterruptedException
     */
    @ApiOperation(value = "秒杀红包测试接口", notes = "秒杀红包测试接口")
    @GetMapping(value = "/redEnvelope")
    public String redEnvelope2() throws InterruptedException {
        String lockKey = "hong";
        //红包份数
        int number = 3;
        //1、首先获取锁的对象
        RLock lock = redisson.getLock(lockKey);
        try {
            //2、添加一个锁（默认超时时间30秒，其另外redisson后台会默认开一个分线程从而为这把锁自动续命）
            lock.tryLock();
            int bigBao = Integer.parseInt(stringRedisTemplate.opsForValue().get("hongbao"));//jedis.get(key)
            if (bigBao > 0) {
                List<Integer> gifts = RandomGiftUtils.randomGifts(bigBao, number);
                for (int i = 0; i < gifts.size(); i++) {
                    int realBigBao = bigBao - gifts.get(i);
                    stringRedisTemplate.opsForValue().set("hongbao", realBigBao + "");
                    System.out.println("当前时间：" + System.currentTimeMillis() + ">>>>>>>>>" + "抢包成功，扣减红包金额:" + realBigBao + "");
                }
            } else {
                System.out.println("抢包失败，扣减红包金额不足>>>>>>>>>" + System.currentTimeMillis());
            }
        } finally {
            //3、释放锁
            lock.unlock();
        }
        return "end";
    }


}
